// 📁 service/impl/FineServiceImpl.java (完整修复版)
package com.library.management.service.impl;

import com.library.management.entity.BorrowRecord;
import com.library.management.entity.Fine;
import com.library.management.entity.User;
import com.library.management.enums.FineReason;
import com.library.management.enums.FineStatus;
import com.library.management.repository.BorrowRecordRepository;
import com.library.management.repository.FineRepository;
import com.library.management.repository.UserRepository;
import com.library.management.service.FineService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

/**
 * 罚款服务实现类
 * 处理罚款相关的业务逻辑实现
 */
@Service
@Transactional
@RequiredArgsConstructor
@Slf4j
public class FineServiceImpl implements FineService {

    private final FineRepository fineRepository;
    private final UserRepository userRepository;
    private final BorrowRecordRepository borrowRecordRepository;

    @Override
    public Fine save(Fine fine) {
        log.info("保存罚款记录: {}", fine.getId());
        return fineRepository.save(fine);
    }

    @Override
    public Fine update(Long id, Fine fine) {
        log.info("更新罚款记录: {}", id);

        Fine existingFine = fineRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("罚款记录不存在: " + id));

        // 更新允许修改的字段
        existingFine.setFineAmount(fine.getFineAmount());
        existingFine.setFineReason(fine.getFineReason());
        existingFine.setDescription(fine.getDescription());
        existingFine.setPaidAmount(fine.getPaidAmount());
        existingFine.setPaymentDate(fine.getPaymentDate());
        existingFine.setPaymentMethod(fine.getPaymentMethod());
        existingFine.setStatus(fine.getStatus());

        return fineRepository.save(existingFine);
    }

    @Override
    public void delete(Long id) {
        log.info("删除罚款记录: {}", id);

        Fine fine = fineRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("罚款记录不存在: " + id));

        // 检查罚款是否已支付
        if (fine.getStatus() == FineStatus.PAID || fine.getStatus() == FineStatus.PARTIAL) {
            throw new RuntimeException("已支付的罚款记录不能删除");
        }

        fineRepository.deleteById(id);
    }

    @Override
    public Optional<Fine> findById(Long id) {
        return fineRepository.findById(id);
    }

    @Override
    public Fine getById(Long id) {
        return fineRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("罚款记录不存在: " + id));
    }

    @Override
    public List<Fine> findAll() {
        return fineRepository.findAll();
    }

    @Override
    public Page<Fine> findAll(Pageable pageable) {
        return fineRepository.findAll(pageable);
    }

    @Override
    public boolean exists(Long id) {
        return fineRepository.existsById(id);
    }

    @Override
    public List<Fine> findByUser(User user) {
        return fineRepository.findByUser(user);
    }

    @Override
    public List<Fine> findByUserId(Long userId) {
        return fineRepository.findByUserId(userId);
    }

    @Override
    public List<Fine> findByStatus(FineStatus status) {
        return fineRepository.findByStatus(status);
    }

    @Override
    public List<Fine> findByFineReason(FineReason reason) {
        return fineRepository.findByFineReason(reason);
    }

    @Override
    public List<Fine> findUnpaidFines() {
        return fineRepository.findUnpaidFines();
    }

    @Override
    public List<Fine> findPartialPaidFines() {
        return fineRepository.findPartialPaidFines();
    }

    @Override
    public List<Fine> findPaidFines() {
        return fineRepository.findPaidFines();
    }

    @Override
    public List<Fine> findWaivedFines() {
        return fineRepository.findWaivedFines();
    }

    @Override
    public BigDecimal sumFineAmountByUserId(Long userId) {
        return fineRepository.sumFineAmountByUserId(userId).orElse(BigDecimal.ZERO);
    }

    @Override
    public BigDecimal sumUnpaidFineAmountByUserId(Long userId) {
        return fineRepository.sumUnpaidFineAmountByUserId(userId).orElse(BigDecimal.ZERO);
    }

    @Override
    public Fine payFine(Long fineId, BigDecimal amount, String paymentMethod) {
        log.info("支付罚款: {}, 金额: {}", fineId, amount);

        Fine fine = getById(fineId);
        boolean success = fine.payFine(amount, paymentMethod);
        if (!success) {
            throw new RuntimeException("罚款支付失败");
        }

        return fineRepository.save(fine);
    }

    @Override
    public Fine waiveFine(Long fineId, String reason) {
        log.info("减免罚款: {}", fineId);

        Fine fine = getById(fineId);
        fine.waiveFine();
        if (reason != null && !reason.trim().isEmpty()) {
            String newDescription = fine.getDescription() + " [减免原因: " + reason + "]";
            fine.setDescription(newDescription);
        }

        return fineRepository.save(fine);
    }

    @Override
    public Fine createOverdueFine(Long borrowRecordId, BigDecimal fineRate) {
        log.info("创建逾期罚款，借阅记录: {}", borrowRecordId);

        BorrowRecord borrowRecord = borrowRecordRepository.findById(borrowRecordId)
                .orElseThrow(() -> new RuntimeException("借阅记录不存在: " + borrowRecordId));

        // 检查是否已经存在罚款记录
        Optional<Fine> existingFine = findByBorrowRecordId(borrowRecordId);
        if (existingFine.isPresent()) {
            throw new RuntimeException("该借阅记录已存在罚款记录");
        }

        // 计算罚款金额
        int overdueDays = borrowRecord.getOverdueDays();
        BigDecimal fineAmount = fineRate.multiply(BigDecimal.valueOf(overdueDays));

        Fine fine = new Fine();
        fine.setUser(borrowRecord.getUser());
        fine.setBorrowRecord(borrowRecord);
        fine.setFineAmount(fineAmount);
        fine.setFineReason(FineReason.OVERDUE);
        fine.setDescription(String.format("图书《%s》逾期%d天，按每天%.2f元计算罚款",
                borrowRecord.getBook().getTitle(), overdueDays, fineRate));

        return fineRepository.save(fine);
    }

    @Override
    public Fine createLostFine(Long borrowRecordId, BigDecimal bookPrice) {
        log.info("创建遗失罚款，借阅记录: {}", borrowRecordId);

        BorrowRecord borrowRecord = borrowRecordRepository.findById(borrowRecordId)
                .orElseThrow(() -> new RuntimeException("借阅记录不存在: " + borrowRecordId));

        // 检查是否已经存在罚款记录
        Optional<Fine> existingFine = findByBorrowRecordId(borrowRecordId);
        if (existingFine.isPresent()) {
            throw new RuntimeException("该借阅记录已存在罚款记录");
        }

        // 遗失罚款通常是图书价格的2-5倍，这里设为3倍
        BigDecimal fineAmount = bookPrice.multiply(BigDecimal.valueOf(3));

        Fine fine = new Fine();
        fine.setUser(borrowRecord.getUser());
        fine.setBorrowRecord(borrowRecord);
        fine.setFineAmount(fineAmount);
        fine.setFineReason(FineReason.LOST);
        fine.setDescription(String.format("图书《%s》遗失，原价%.2f元，罚款%.2f元",
                borrowRecord.getBook().getTitle(), bookPrice, fineAmount));

        return fineRepository.save(fine);
    }

    @Override
    public Fine createDamagedFine(Long borrowRecordId, BigDecimal damageAmount, String description) {
        log.info("创建损坏罚款，借阅记录: {}", borrowRecordId);

        BorrowRecord borrowRecord = borrowRecordRepository.findById(borrowRecordId)
                .orElseThrow(() -> new RuntimeException("借阅记录不存在: " + borrowRecordId));

        // 检查是否已经存在罚款记录
        Optional<Fine> existingFine = findByBorrowRecordId(borrowRecordId);
        if (existingFine.isPresent()) {
            throw new RuntimeException("该借阅记录已存在罚款记录");
        }

        Fine fine = new Fine();
        fine.setUser(borrowRecord.getUser());
        fine.setBorrowRecord(borrowRecord);
        fine.setFineAmount(damageAmount);
        fine.setFineReason(FineReason.DAMAGED);
        fine.setDescription("图书损坏罚款: " + description);

        return fineRepository.save(fine);
    }

    @Override
    public List<Fine> findOverdueFines(int expiryDays) {
        LocalDateTime thresholdTime = LocalDateTime.now().minusDays(expiryDays);
        return fineRepository.findOverdueFines(thresholdTime);
    }

    @Override
    public List<Object[]> countFinesByStatus() {
        return fineRepository.countFinesByStatus();
    }

    @Override
    public Optional<Fine> findByBorrowRecordId(Long borrowRecordId) {
        return fineRepository.findByBorrowRecordId(borrowRecordId);
    }

    @Override
    public BigDecimal sumFineAmountByPeriod(LocalDateTime startTime, LocalDateTime endTime) {
        return fineRepository.sumFineAmountByPeriod(startTime, endTime).orElse(BigDecimal.ZERO);
    }

    @Override
    public boolean isFineFullyPaid(Long fineId) {
        Fine fine = getById(fineId);
        return fine.isFullyPaid();
    }

    @Override
    public BigDecimal getRemainingAmount(Long fineId) {
        Fine fine = getById(fineId);
        return fine.getRemainingAmount();
    }

    @Override
    public void processExpiredFines(int expiryDays) {
        List<Fine> expiredFines = findOverdueFines(expiryDays);
        for (Fine fine : expiredFines) {
            // 这里可以添加过期罚款的处理逻辑，比如发送提醒、增加滞纳金等
            log.info("处理过期罚款: {}, 金额: {}", fine.getId(), fine.getRemainingAmount());
        }
        log.info("处理了 {} 个过期罚款记录", expiredFines.size());
    }
}